//
//  MRServer.m
//  McRemoteServer
//
//  Created by Magic on 12/8/11.
//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//

#import "MRServer.h"
#import "GCDAsyncSocket.h"

#define kBigDataChunckSize 500
#define kBigDataTag 129

@interface MRServer () {
    NSNetService *_netService;
	GCDAsyncSocket *_asyncSocket;
	NSMutableArray *_connectedSockets;
    GCDAsyncSocket *_currentSocket;
    UInt16 _port;    
    
    //NSMutableData *_bigDataBuffer;
    //NSUInteger _sentOffset;
}

@property (nonatomic,retain) GCDAsyncSocket *currentSocket;

@end

@implementation MRServer 

@synthesize delegate;
@synthesize currentSocket = _currentSocket;

+ (MRServer *)sharedServer
{
    static MRServer *sharedServer;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        sharedServer = [[MRServer alloc] init];
    });
    
    return sharedServer;
}

- (id)init {
    self = [super init];
    if (self) {
        //_bigDataBuffer = [[NSMutableData alloc] initWithCapacity:1000];
        
        // Create our socket.
        // We tell it to invoke our delegate methods on the main thread.        
        _asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        // Create an array to hold accepted incoming connections.        
        //_connectedSockets = [[NSMutableArray alloc] init];
        
    }
    return self;
}

- (void)dealloc {
    [_asyncSocket release];
    self.currentSocket = nil;
    [_netService release];
    [super dealloc];
}

- (void)start
{
    // Now we tell the socket to accept incoming connections.
    // We don't care what port it listens on, so we pass zero for the port number.
    // This allows the operating system to automatically assign us an available port.        
    NSError *err = nil;
    if ([_asyncSocket acceptOnPort:0 error:&err])
    {
        // So what port did the OS give us?            
        _port = [_asyncSocket localPort];
        
    }
    else
    {
        NSLog(@"Error in acceptOnPort:error: -> %@", err);
    }

}

#pragma mark AsyncSocket Callback

- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
	NSLog(@"Accepted new socket from %@:%hu", [newSocket connectedHost], [newSocket connectedPort]);
	
	// The newSocket automatically inherits its delegate & delegateQueue from its parent.
	
	//[_connectedSockets addObject:newSocket];
    
    if (!self.currentSocket) {
        self.currentSocket = newSocket;
        self.currentSocket.delegate = self;
        
        if ([delegate respondsToSelector:@selector(serverDidAcceptNewConnection)]) {
            [delegate serverDidAcceptNewConnection];
        }

        [[NSNotificationCenter defaultCenter] postNotificationName:@"NewConnection" object:nil];
        
    }

}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
	//[_connectedSockets removeObject:sock];
    self.currentSocket = nil;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ConnectionLost" object:nil];
}


#pragma mark Bonjour Callback

- (void)enableBonjourWithServiceType:(NSString *)type
{
    // Create and publish the bonjour service.
    // Obviously you will be using your own custom service type.            
    _netService = [[NSNetService alloc] initWithDomain:@"local."
                                                  type:[NSString stringWithFormat:@"_%@._tcp.", type]
                                                  name:@""
                                                  port:_port];            
    [_netService setDelegate:self];
    [_netService publish];
    
    // You can optionally add TXT record stuff            
    /*NSMutableDictionary *txtDict = [NSMutableDictionary dictionaryWithCapacity:2];
     
     [txtDict setObject:@"moo" forKey:@"cow"];
     [txtDict setObject:@"quack" forKey:@"duck"];
     
     NSData *txtData = [NSNetService dataFromTXTRecordDictionary:txtDict];
     [netService setTXTRecordData:txtData];*/
}

- (void)netServiceDidPublish:(NSNetService *)ns
{
	NSLog(@"Bonjour Service Published: domain(%@) type(%@) name(%@) port(%i)",
			  [ns domain], [ns type], [ns name], (int)[ns port]);
}

- (void)netService:(NSNetService *)ns didNotPublish:(NSDictionary *)errorDict
{
	// Override me to do something here...
	// 
	// Note: This method in invoked on our bonjour thread.
	
	NSLog(@"Failed to Publish Service: domain(%@) type(%@) name(%@) - %@",
               [ns domain], [ns type], [ns name], errorDict);
}

- (void)readDataToLength:(NSUInteger)length tag:(long)tag
{
    [_currentSocket readDataToLength:length withTimeout:-1 tag:tag];
}

//- (void)readDataToData:(NSData *)data tag:(long)tag
//{
//    [_currentSocket readDataToData:data withTimeout:-1 tag:tag];
//}
//
//- (void)readDataToString:(void *)string length:(NSUInteger)length tag:(long)tag;
//{
//    NSData *data = [NSData dataWithBytes:string length:length];
//    [_currentSocket readDataToData:data withTimeout:-1 tag:tag];
//}

//- (void)writeData
//{    
//    
//    NSUInteger dataLeft,dataToSend;
//    
//    @synchronized(_bigDataBuffer)
//    {
//        dataLeft = [_bigDataBuffer length] - _sentOffset;
//    }
//    
//    
//    dataToSend = dataLeft > kBigDataChunckSize ? kBigDataChunckSize : dataLeft;
//    
//    [_currentSocket writeData:[_bigDataBuffer subdataWithRange:NSMakeRange(_sentOffset, dataToSend)] withTimeout:3 tag:1];
//    
//    _sentOffset += dataToSend;
//}
//
//- (void)writeBigData:(NSData *)data
//{
//    NSUInteger sent = 0;
//    NSUInteger size = [data length];
//    while (1) {
//        if (sent+kBigDataChunckSize < size) {
//            [_currentSocket writeData:[data subdataWithRange:NSMakeRange(sent, kBigDataChunckSize)] withTimeout:-1 tag:1];
//            sent += kBigDataChunckSize;
//        }
//        else {
//            [_currentSocket writeData:[data subdataWithRange:NSMakeRange(sent, size-sent)] withTimeout:-1 tag:1];
//            break;
//        }
//    }
//
//}

- (void)writeData:(NSData *)data tag:(long)tag
{    
//    if ([data length] > kBigDataChunckSize) {
//        [self writeBigData:data];
//        
//    }
//    else {
        [_currentSocket writeData:data withTimeout:3 tag:1];

//    }
//    @synchronized(_bigDataBuffer)
//    {
//        [_bigDataBuffer appendData:data];
//        
//        
//    }
//    
//    if (_sentOffset == 0) {
//        [self writeData];
//    }
    

}


- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    NSLog(@"did write data");
    
//    @synchronized(_bigDataBuffer)
//    {
//        if (_sentOffset < [_bigDataBuffer length]) {
//            [self performSelector:@selector(writeData) withObject:nil afterDelay:0.2];
//        }
//        else { //_sentOffset == [_bigDataBuffer length]
//            _sentOffset = 0;
//            [_bigDataBuffer setLength:0];
//        }
//        
//    }
}

//- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag
//                 elapsed:(NSTimeInterval)elapsed
//               bytesDone:(NSUInteger)length
//{
//    @synchronized(_bigDataBuffer)
//    {
//        if (_sentOffset < [_bigDataBuffer length]) {
//            [self performSelector:@selector(writeData) withObject:nil afterDelay:0.2];
//        }
//        else { //_sentOffset == [_bigDataBuffer length]
//            _sentOffset = 0;
//            [_bigDataBuffer setLength:0];
//        }
//    }
//    return 0;
//}


- (void)socket:(GCDAsyncSocket *)sender didReadData:(NSData *)data withTag:(long)tag
{
    [delegate didReadData:data withTag:tag];
}

@end
